pub build_config: BuildConfig,
pub build_scripts: HashMap<Unit<'a>, Arc<BuildScripts>>,
pub links: Links<'a>,
+ pub used_in_plugin: HashSet<Unit<'a>>,
host: Layout,
target: Option<Layout>,
build_scripts: HashMap::new(),
build_explicit_deps: HashMap::new(),
links: Links::new(),
+ used_in_plugin: HashSet::new(),
})
}
Ok(())
}
+ /// Builds up the `used_in_plugin` internal to this context from the list of
+ /// top-level units.
+ ///
+ /// This will recursively walk `units` and all of their dependencies to
+ /// determine which crate are going to be used in plugins or not.
+ pub fn build_used_in_plugin_map(&mut self, units: &[Unit<'a>])
+ -> CargoResult<()> {
+ let mut visited = HashSet::new();
+ for unit in units {
+ try!(self.walk_used_in_plugin_map(unit,
+ unit.target.for_host(),
+ &mut visited));
+ }
+ Ok(())
+ }
+
+ fn walk_used_in_plugin_map(&mut self,
+ unit: &Unit<'a>,
+ is_plugin: bool,
+ visited: &mut HashSet<(Unit<'a>, bool)>)
+ -> CargoResult<()> {
+ if !visited.insert((*unit, is_plugin)) {
+ return Ok(())
+ }
+ if is_plugin {
+ self.used_in_plugin.insert(*unit);
+ }
+ for unit in try!(self.dep_targets(unit)) {
+ try!(self.walk_used_in_plugin_map(&unit,
+ is_plugin || unit.target.for_host(),
+ visited));
+ }
+ Ok(())
+ }
+
/// Returns the appropriate directory layout for either a plugin or not.
pub fn layout(&self, unit: &Unit) -> LayoutProxy {
let primary = unit.pkg.package_id() == self.resolve.root();
try!(cx.prepare());
try!(cx.probe_target_info(&units));
+ try!(cx.build_used_in_plugin_map(&units));
try!(custom_build::build_map(&mut cx, &units));
for unit in units.iter() {
cmd.arg("-C").arg(&format!("opt-level={}", opt_level));
}
+ // If a panic mode was configured *and* we're not ever going to be used in a
+ // plugin, then we can compile with that panic mode.
+ //
+ // If we're used in a plugin then we'll eventually be linked to libsyntax
+ // most likely which isn't compiled with a custom panic mode, so we'll just
+ // get an error if we actually compile with that. This fixes `panic=abort`
+ // crates which have plugin dependencies, but unfortunately means that
+ // dependencies shared between the main application and plugins must be
+ // compiled without `panic=abort`. This isn't so bad, though, as the main
+ // application will still be compiled with `panic=abort`.
if let Some(panic) = panic.as_ref() {
- cmd.arg("-C").arg(format!("panic={}", panic));
+ if !cx.used_in_plugin.contains(unit) {
+ cmd.arg("-C").arg(format!("panic={}", panic));
+ }
}
// Disable LTO for host builds as prefer_dynamic and it are mutually
[ERROR] could not exec the linker [..]
"));
}
+
+#[test]
+fn panic_abort_plugins() {
+ if !is_nightly() {
+ return
+ }
+
+ let bar = project("bar")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [profile.dev]
+ panic = 'abort'
+
+ [dependencies]
+ foo = { path = "foo" }
+ "#)
+ .file("src/lib.rs", "")
+ .file("foo/Cargo.toml", r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [lib]
+ plugin = true
+ "#)
+ .file("foo/src/lib.rs", r#"
+ #![feature(rustc_private)]
+ extern crate syntax;
+ "#);
+
+ assert_that(bar.cargo_process("build"),
+ execs().with_status(0));
+}
+
+#[test]
+fn shared_panic_abort_plugins() {
+ if !is_nightly() {
+ return
+ }
+
+ let bar = project("top")
+ .file("Cargo.toml", r#"
+ [package]
+ name = "top"
+ version = "0.0.1"
+ authors = []
+
+ [profile.dev]
+ panic = 'abort'
+
+ [dependencies]
+ foo = { path = "foo" }
+ bar = { path = "bar" }
+ "#)
+ .file("src/lib.rs", "
+ extern crate bar;
+ ")
+ .file("foo/Cargo.toml", r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [lib]
+ plugin = true
+
+ [dependencies]
+ bar = { path = "../bar" }
+ "#)
+ .file("foo/src/lib.rs", r#"
+ #![feature(rustc_private)]
+ extern crate syntax;
+ extern crate bar;
+ "#)
+ .file("bar/Cargo.toml", r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+ "#)
+ .file("bar/src/lib.rs", "");
+
+ assert_that(bar.cargo_process("build"),
+ execs().with_status(0));
+}